// Copyright (c) 2022 Huawei Device Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_BASE_OHOS_MEDIA_PLAYER_BRIDGE_H_
#define MEDIA_BASE_OHOS_MEDIA_PLAYER_BRIDGE_H_

#include <deque>

#include "base/memory/weak_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/timer/timer.h"
#include "graphic_adapter.h"
#include "media/base/media_export.h"
#include "media_adapter.h"
#include "net/cookies/site_for_cookies.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace media {
class MEDIA_EXPORT OHOSMediaPlayerBridge {
 public:
  class Client {
   public:
    virtual void OnFrameAvailable(int fd,
                                  uint32_t size,
                                  int32_t coded_width,
                                  int32_t coded_height,
                                  int32_t visible_width,
                                  int32_t visible_height,
                                  int32_t format) = 0;

    // Called when media duration is first detected or changes.
    virtual void OnMediaDurationChanged(base::TimeDelta duration) = 0;

    // Called when playback completed.
    virtual void OnPlaybackComplete() = 0;

    // Called when error happens.
    virtual void OnError(int error) = 0;

    // Called when video size has changed.
    virtual void OnVideoSizeChanged(int width, int height) = 0;

    // Called when player InterruptEvent.
    virtual void OnPlayerInterruptEvent(int32_t value) = 0;

    virtual void OnAudioStateChanged(bool isAudible) = 0;
  };

  enum MediaErrorType {
    MEDIA_ERROR_FORMAT,
    MEDIA_ERROR_DECODE,
    MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK,
    MEDIA_ERROR_INVALID_CODE,
    MEDIA_ERROR_SERVER_DIED,
  };

  OHOSMediaPlayerBridge(const GURL& url,
                        const net::SiteForCookies& site_for_cookies,
                        const url::Origin& top_frame_origin,
                        const std::string& user_agent,
                        bool hide_url_log,
                        Client* client,
                        bool allow_credentials,
                        bool is_hls);
  virtual ~OHOSMediaPlayerBridge();

  OHOSMediaPlayerBridge(const OHOSMediaPlayerBridge&) = delete;
  OHOSMediaPlayerBridge& operator=(const OHOSMediaPlayerBridge&) = delete;

  int32_t Initialize();
  void Start();
  void Pause();
  void SeekTo(base::TimeDelta time);
  base::TimeDelta GetDuration();
  void SetVolume(float volume, bool ismuted);
  base::TimeDelta GetMediaTime();
  void FinishPaint(int fd);
  void SetPlaybackSpeed(OHOS::NWeb::PlaybackRateMode mode);

  void OnEnd();
  void OnError(int32_t errorCode);
  void OnBufferAvailable(
      std::unique_ptr<OHOS::NWeb::SurfaceBufferAdapter> buffer);
  void OnPlayerStateUpdate(
      OHOS::NWeb::PlayerAdapter::PlayerStates player_state);
  void OnVideoSizeChanged(int32_t width, int32_t height);
  void OnPlayerInterruptEvent(int32_t value);
  void SeekDone();

 private:
  int32_t SetFdSource(const std::string& path);
  void Prepare();
  void StartInternal();
  void SeekInternal(base::TimeDelta time);
  void PropagateDuration(base::TimeDelta duration);
  bool IsAudible(float volume);

  const std::string surfaceFormat = "SURFACE_FORMAT";
  std::unique_ptr<OHOS::NWeb::PlayerAdapter> player_ = nullptr;
  std::deque<std::unique_ptr<OHOS::NWeb::SurfaceBufferAdapter>> cached_buffers_;
  std::unique_ptr<OHOS::NWeb::IConsumerSurfaceAdapter> consumer_surface_ =
      nullptr;
  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
  Client* client_;
  GURL url_;
  bool prepared_;
  bool pending_play_;
  bool should_seek_on_prepare_;
  float volume_;
  float current_volume_ = 0;
  bool is_muted_ = false;
  bool should_set_volume_on_prepare_;
  base::TimeDelta duration_;
  base::TimeDelta pending_seek_;
  OHOS::NWeb::PlayerAdapter::PlayerStates player_state_;

  // MediaPlayer is unable to handle Seek request when playback end. We should
  // pending the SeekTo request until its playback state changed.
  bool seeking_on_playback_complete_;
#if defined(RK3568)
  bool is_hls_;
#endif

  base::WeakPtrFactory<OHOSMediaPlayerBridge> weak_factory_{this};
  int32_t seek_done_count_ = 0;
};
}  // namespace media

#endif  // MEDIA_BASE_OHOS_MEDIA_PLAYER_BRIDGE_H_
